#include <iostream>
#include <cstdlib>
#include <string>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>

int cnt = 0;

void catchsig(int signo)
{
    std::cout << "捕捉到一个信号,编号为：" << signo <<"  cnt: "<<cnt<< std::endl;
    exit(1);
}

/*演示产生信号的几种方式*/

int main(int argc, char *argv[])
{
    //////////////////////////////////////////////////////////////////////////////////////////////
    // 1. 可以通过键盘的方式发送信号
    //  while(true)
    //  {
    //      std::cout<<"我正在运行....."<<std::endl;
    //      sleep(1);
    //  }

    //////////////////////////////////////////////////////////////////////////////////////////////

    // 2. 系统调用向目标进程发送信号
    // kill()可以向任意进程发送信号
    // raise()给自己发送信号--kill(getpid(),任意信号)
    // abort()给自己发送指定信号SIGABRT(6)，kill(getpid(),SIGABRT)
    // 关于信号的理解：有很多情况，大部分进程接收到信号，默认的动作就是终止进程
    // 那么信号的意义：有很多不同的信号，代表着不同的事件，它们的最终处理方式可以一样，但是代表的意义不一样
    //  if(argc!=3)
    //  {
    //      std::cout<<"\nUsage:"<<argv[0]<<" pid signal\n"<<std::endl;
    //      exit(1);
    //  }
    //  pid_t id=atoi(argv[1]);
    //  int signo=atoi(argv[2]);
    //  int n=kill(id,signo);//系统接口，给进程号为id的进程发送signo信号
    // if(n!=0)
    //  {
    //      perror("kill");
    //  }
    //  int cnt =0;
    //  while(cnt<=10)
    //  {
    //      std::cout<<"我是一个进程，我正在运行......"<<cnt++<<std::endl;
    //      sleep(1);
    //      if(cnt>=5)
    //          // raise(2);//给自己发送2号信号---类似于在键盘中输入Ctrl+c
    //      abort();
    //  }
    //////////////////////////////////////////////////////////////////////////////////////////////
    // 3.硬件异常产生信号
    // 信号的产生不一定非得用户显示发送
    //
    signal(8, catchsig); // 因为除零操作会导致OS会向进程发送8号信号,尝试对8号信号进行捕捉
    // int a = 10;
    // a /= 0; // Floating point exception(浮点异常),在命令行上显示了这段信息---SIGFPE（8）
    // 为什么除0 会终止进程？当前进程会受到来自OS系统的信号(告知)，SIGFPE

    // 会出现不断调用我们自定义的捕捉方法catchsig，也就是说OS不断的向进程发送了8号信号，
    // 问题是，我们只是运行了一次除零操作，为什么OS会不断的发送信号呢？
    // OS如何得知应该给当前进程发送8号信号的-- OS怎么知道我除0了呢？？---CPU会异常
    //--cpu内部会有一个状态寄存器中的溢出标志位,除零会导致标志位为1
    //-- CPU内部的寄存器只有一份，但是寄存器中的内容，属于当前进程的上下文！
    // 受到信号，不一定会引起进程退出 -- 没有退出，有可能还会被调到
    // 受到信号，不一定会引起进程退出 -- 没有退出，有可能还会被调到
    // 该进程有没有能力或者动作修正这个问题呢？没有
    // 当进程被切换的时候，就有无数次状态寄存器被保存和恢复的过程
    // 所以每一次恢复的时候，就让OS识别到了CPU内部的状态寄存器中的溢出标志位是1

    //
    // while (true)
    // {
    //     std::cout << "我正在运行中...." << std::endl;
    //     sleep(1);
    //     int *p = nullptr;
    //     // OS怎么知道呢？？我野指针了呢？
    //     // 为什么 野指针 就会崩溃呢？因为OS会给当前进程发送指定的11号信号
    //     *p = 100; // Segmentation fault（段错误）命令行上显示了这段信息---SIGFPE（11）
    // }

    //////////////////////////////////////////////////////////////////////////////////////////////
    // 4.软件条件--"闹钟"其实就是用软件实现的
    // unsigned int alarm(unsigned int seconds);
    signal(SIGALRM, catchsig);
    //alarm(1); // 倒计时多少秒之后就向进程发送14号信号---SIGALRM

    // 我们可以随带统计1S左右，我们的计算机能够将数据累计多少次!
    // IO其实很慢---在需要输出语句的时候cnt大概值为20594
    //没有IO的时候 cnt=345252968
    // while (true)
    // {
    //     // std::cout<<"我正在运行...."<<cnt++<<std::endl;
    //     cnt++;
    // }


////////////////////////////////////////////////////////////////
    // 核心转储---在命名行中输入ulimit -a看看是否打开了--core file size          (blocks, -c) 0
    //为零就是没有打开(云服务器默认关闭的) --可以输入ulimit -c 1024,设置打开
    //Segmentation fault (core dumped)
    //打开之后，让下面程序运行，会发生Segmentation fault--段错误,如果没开core file size,就没有(core dumped)这提示
    //打开之后,会在当前目录下生成一个文件--core.出现问题进程的pid  这个文件是存储了该进程的调试信息，方便后续调试定位错误
    //注意有些信号不会产生这样的文件，只有默认动作为Core的信号才会
    //在gdb中输入：core-file 这个core.进程pid的文件即可定位到错误的位置
    while (true)
    {
        int a[10];
        a[100000] = 100;
    }

    return 0;
}
